#include "vpss_grp_imp.h"
#include "guard.h"

#include "mpi_vpss.h"

using namespace Json;
using namespace detu_infra;

namespace detu_media
{

constexpr const VPSS_GRP_ATTR_S VpssGrpImp::defaultGrpAttr;

VpssGrpImp::VpssGrpImp(void)
    : VpssGrp(), fGrpId(-1), fInited(false), fRef(0), fMutex(MUTEX_RECURSIVE)
{
    memset(&fGrpAttr, 0, sizeof(VPSS_GRP_ATTR_S));
}

VpssGrpImp::~VpssGrpImp(void)
{
	if (isInited())
	{
		deInit();
	}
}

S_Result VpssGrpImp::callbackAll(const void* clientData, const std::string& name, const Json::Value& oldConfig, const Json::Value& newConfig, Json::Value& response)
{
	S_Result ret = S_ERROR;

	do
	{
		VpssGrpImp& grp = *(VpssGrpImp *)clientData;
		if (S_OK != grp.callback(clientData, name, oldConfig, newConfig, response))
		{
			break;
		}
		ret = S_OK;
	}while (0);

	return ret;
}

S_Result VpssGrpImp::callback(const void* clientData, const std::string& name, const Json::Value& oldConfig, const Json::Value& newConfig, Json::Value& response)
{
	S_Result ret = S_ERROR;
	do
	{
		if (newConfig.isMember("grpAttr"))
		{
			if (S_OK != setGrpAttr(oldConfig["grpAttr"], newConfig["grpAttr"]))
			{
				break;
			}
		}

		ret = S_OK;
	}while (0);

	return ret;
}

S_Result VpssGrpImp::setGrpAttr(const Json::Value& oldConfig, const Json::Value& newConfig)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (!newConfig.compare(oldConfig))
		{
			ret = S_OK;
			break;
		}
		if (newConfig.isMember("frameRate"))
		{
			const Value& frameRate = newConfig["frameRate"];

			if (frameRate.isMember("srcFrameRate") && frameRate["srcFrameRate"].isIntegral())
				fGrpAttr.stFrameRate.s32SrcFrameRate = frameRate["srcFrameRate"].asInt();

			if (frameRate.isMember("dstFrameRate") && frameRate["dstFrameRate"].isIntegral())
				fGrpAttr.stFrameRate.s32DstFrameRate = frameRate["dstFrameRate"].asInt();
		}
		if (isStarted())
		{
			HI_S32 s32Ret = HI_MPI_VPSS_SetGrpAttr(fGrpId, &fGrpAttr);
			if (s32Ret != HI_SUCCESS)
			{
				printf("HI_MPI_VPSS_SetGrpAttr failed with %#x! grpId: %d\n", s32Ret, fGrpId);
				break;
			}

		}

		ret = S_OK;
	}while (0);

	return ret;


}


S_Result VpssGrpImp::init(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		fGrpId = (config.isMember("grpId") && config["grpId"].isIntegral()) ? config["grpId"].asInt() : -1;
		fGrpAttr = defaultGrpAttr;
		if (config.isMember("grpAttr"))
		{
			const Value& grpAttr = config["grpAttr"];

			if (grpAttr.isMember("maxWidth") && grpAttr["maxWidth"].isIntegral())
				fGrpAttr.u32MaxW = grpAttr["maxWidth"].asUInt();

			if (grpAttr.isMember("maxHeight") && grpAttr["maxHeight"].isIntegral())
				fGrpAttr.u32MaxH = grpAttr["maxHeight"].asUInt();

			if (grpAttr.isMember("frameRate"))
			{
				const Value& frameRate = grpAttr["frameRate"];

				if (frameRate.isMember("srcFrameRate") && frameRate["srcFrameRate"].isIntegral())
					fGrpAttr.stFrameRate.s32SrcFrameRate = frameRate["srcFrameRate"].asInt();

				if (frameRate.isMember("dstFrameRate") && frameRate["dstFrameRate"].isIntegral())
					fGrpAttr.stFrameRate.s32DstFrameRate = frameRate["dstFrameRate"].asInt();
			}
		}

		if (config.isMember("pipe"))
		{
			const Value& pipeCfg = config["pipe"];
			if (S_OK != initPipe(pipeCfg))
			{
				printf("init pipe failed! grpId: %d\n", fGrpId);
				break;
			}
		}
		else
		{
			printf("pipe config not exist! grpId: %d\n", fGrpId);
			break;
		}

		if (config.isMember("chn"))
		{
			const Value& chnCfg = config["chn"]; 
			if (S_OK != initChn(chnCfg))
			{
				printf("init chn failed! grpId: %d\n", fGrpId);
				break;
			}
		}
		else
		{
			printf("chn config not exist! grpId: %d\n", fGrpId);
			break;
		}

		ret = S_OK;
		fInited = true;
	}
	while(0);

	return ret;
}

S_Result VpssGrpImp::deInit()
{
	Guard guard(fMutex);
	if (isStarted())
	{
		fRef = 1;
		stop();
	}

	deInitChn();
	deInitPipe();
	fGrpId = -1;
	memset(&fGrpAttr, 0, sizeof(VPSS_GRP_ATTR_S));
	fInited = false;

	return S_OK;
}

S_Result VpssGrpImp::start()
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (fRef < 0)
		{
			printf("start failed, fRef: %d < 0! grpId: %d\n", fRef, fGrpId);
			break;
		}

		if (fRef > 0)
		{
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("grp Id: %d not inited!\n", fGrpId);
			break;
		}

		HI_S32 s32Ret = HI_MPI_VPSS_CreateGrp(fGrpId, &fGrpAttr);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_CreateGrp failed with %#x! grpId: %d\n", s32Ret, fGrpId);
			break;
		}

		s32Ret = HI_MPI_VPSS_StartGrp(fGrpId);

		if (s32Ret != HI_SUCCESS)
		{
			HI_MPI_VPSS_DestroyGrp(fGrpId);
			printf("HI_MPI_VPSS_StartGrp failed with %#x! grpId: %d\n", s32Ret, fGrpId);
			break;
		}

		if (S_OK != startPipe())
		{
			printf("start pipe failed! grpId: %d\n", fGrpId);
			break;
		}

		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef++;

	return ret;
}

S_Result VpssGrpImp::stop()
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fRef < 1)
		{
			printf("stop failed, fRef: %d < 1! grpId: %d\n", fRef, fGrpId);
			break;
		}

		if (fRef > 1)
		{
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("grp Id: %d not inited!\n", fGrpId);
			break;
		}

		if (S_OK != stopPipe())
		{
			printf("stop pipe failed! grpId: %d\n", fGrpId);
			break;
		}

		HI_S32 s32Ret;

		s32Ret = HI_MPI_VPSS_StopGrp(fGrpId);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_StopGrp failed with %#x! grpId: %d\n", s32Ret, fGrpId);
			break;
		}

		s32Ret = HI_MPI_VPSS_DestroyGrp(fGrpId);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_DestroyGrp failed with %#x! grpId: %d\n", s32Ret, fGrpId);
			break;
		}

		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef--;

	return ret;
}

bool VpssGrpImp::isInited()
{
    return fInited;
}

bool VpssGrpImp::isStarted()
{
    return (fRef > 0);
}

S_Result VpssGrpImp::getChn(const std::string& name, VpssChn** ppVpssChn)
{
	*ppVpssChn = (VpssChn*)fChnMap[name];

	return (*ppVpssChn) ? S_OK : S_ERROR;
}

S_Result VpssGrpImp::getPipe(const std::string& name, VpssPipe** ppVpssPipe)
{
	*ppVpssPipe = (VpssPipe*)fPipeMap[name];

	return (*ppVpssPipe) ? S_OK : S_ERROR;
}

S_Result VpssGrpImp::getId(int &id)
{
    id = fGrpId;

    return S_OK;
}

S_Result VpssGrpImp::initPipe(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (config.isMember("pipes"))
		{
			const Value& pipes = config["pipes"];
			ValueConstIterator iter = pipes.begin();
			for(; iter != pipes.end(); iter++)
			{
				VpssPipeImp& pipe = *new VpssPipeImp(fGrpId);
				if (S_OK != pipe.init(*iter))
				{
					printf("init vpss pipe: \"%s\" failed!\n", iter.name().c_str());
					break;
				}
				fPipeMap[iter.name()] = &pipe;
			}

			if (iter != pipes.end())
			{
				break;
			}

			ret = S_OK;
		}
	}
	while(0);

	if (S_OK != ret)
		deInitPipe();

	return ret;
}

S_Result VpssGrpImp::deInitPipe(void)
{
	Guard guard(fMutex);
	for(PipeMap::iterator iter = fPipeMap.begin(); iter != fPipeMap.end(); iter++)
		if (iter->second)
		{
			delete iter->second;
		}

	fPipeMap.clear();

	return S_OK;
}

S_Result VpssGrpImp::initChn(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (config.isMember("chns"))
		{
			const Value& chns = config["chns"];
			ValueConstIterator iter = chns.begin();
			for(; iter != chns.end(); iter++)
			{
				VpssChnImp& chn = *new VpssChnImp(fGrpId);
				if (S_OK != chn.init(*iter))
				{
					printf("init vpss chn: \"%s\" failed!\n", iter.name().c_str());
					break;
				}
                //printf("huangqianfeng init vpss chn: \"%s\" failed!\n", iter.name().c_str());
				fChnMap[iter.name()] = &chn;
			}

			if (iter != chns.end())
			{
				break;
			}

			ret = S_OK;
		}
	}
	while(0);

	if (S_OK != ret)
		deInitChn();

	return ret;
}

S_Result VpssGrpImp::deInitChn(void)
{
	Guard guard(fMutex);
	for(ChnMap::iterator iter = fChnMap.begin(); iter != fChnMap.end(); iter++)
		if (iter->second)
		{
			delete iter->second;
		}

	fChnMap.clear();

	return S_OK;
}

S_Result VpssGrpImp::startPipe(void)
{
	Guard guard(fMutex);
	PipeMap::iterator iter = fPipeMap.begin();
	for(; iter != fPipeMap.end(); iter++)
		if (iter->second)
		{
			VpssPipeImp& pipe = *iter->second;
			if (S_OK != pipe.start())
			{
				printf("start vpss pipe: \"%s\" failed!\n", iter->first.c_str());
				break;
			}
		}

	return (iter == fPipeMap.end()) ? S_OK : S_ERROR;
}

S_Result VpssGrpImp::stopPipe(void)
{
	Guard guard(fMutex);
	PipeMap::iterator iter = fPipeMap.begin();
	for(; iter != fPipeMap.end(); iter++)
		if (iter->second)
		{
			VpssPipeImp& pipe = *iter->second;
			if (S_OK != pipe.stop())
			{
				printf("stop vpss pipe: \"%s\" failed!\n", iter->first.c_str());
				break;
			}
		}

	return (iter == fPipeMap.end()) ? S_OK : S_ERROR;
}

}

